﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kinect;
using System.Windows.Input;
using System.Windows.Controls;

namespace KinectApplication
{
    public static class ReachMouseInput
    {
        // Settings, constant
        private static double mouseCenterX = System.Windows.SystemParameters.PrimaryScreenWidth / 2; //320.0F;
        private static double mouseCenterY = System.Windows.SystemParameters.PrimaryScreenHeight / 2;//240.0F;
        private const float MouseSensitivity = 2000.0F;
        private const float loseMouseControlTreshold = 0.2F;
        private const float gainMouseControlTreshold = 0.4F;
        public const float requiredGestureAccuracy = 0.8F;

        // Settings, can be updated on the go
        public static bool mouseDragging = false;

        // Mouse dragging memory
        private static double skeletonCordX = 0;
        private static double skeletonCordY = 0;
        private static double mouseCordX = 0;
        private static double mouseCordY = 0;

        // Player memory
        private static bool rightHand = true;
        private static int playerID = -1;

        // Special kinect mousing cursors
        private static Cursor waitCursor;
        private static Cursor MoveCursor;
        private static Cursor leftCursor;
        private static Cursor RightCursor;

        // List of objects that get the new cursor effects
        private static List<UserControl> iconControls = new List<UserControl>();

        // Add to list
        public static void AddUserControl(UserControl iconControl)
        {
            // Tähän räjähtää, ottaa streamina tai suorana hakemistopolkuna
            if (waitCursor == null)
            {
                waitCursor = new Cursor(Environment.CurrentDirectory + "\\Cursors\\waiting.cur");
                MoveCursor = new Cursor(Environment.CurrentDirectory + "\\Cursors\\moving.cur");
                leftCursor = new Cursor(Environment.CurrentDirectory + "\\Cursors\\leftclick.cur");
                RightCursor = new Cursor(Environment.CurrentDirectory + "\\Cursors\\rightclick.cur");
            }

            iconControl.Cursor = waitCursor;
            iconControls.Add(iconControl);
        }

        // Remove from list
        public static void RemoveUserControl(UserControl iconControl)
        {
            iconControls.Remove(iconControl);
        }

        private static void SetCursor(Cursor cursor)
        {
            foreach (UserControl control in iconControls)
            {
                control.Cursor = cursor;
            }
        }

        // Event received from some parser
        public static void InputEvent(List<Player> players)
        {            
            if (playerID == -1)
            { // No previous player, see if we have new volunteers
                foreach (Player player in players)
                {
                    if (player.IsTracked)
                    {
                        if (player.RightHand.Z < (player.RightShoulder.Z - gainMouseControlTreshold))
                        {
                            if ((!mouseDragging) || (player.RightHand.HighGesture != HandGestures.None))
                            {
                                playerID = player.Id;
                                // TODO: DebugMessage = "Player " + playerID + " started mousing. (Right hand)";
                                rightHand = true;

                                // Starting location for hand when doing mousetracking
                                skeletonCordX = player.RightHand.X * MouseSensitivity + mouseCenterX;
                                skeletonCordY = (player.RightHand.Y * -1) * MouseSensitivity + mouseCenterY;
                            }

                        }
                        else if (player.LeftHand.Z < (player.LeftShoulder.Z - gainMouseControlTreshold))
                        {
                            if ((!mouseDragging) || (player.LeftHand.HighGesture != HandGestures.None))
                            {
                                playerID = player.Id;
                                // TODO: DebugMessage = "Player " + playerID + " started mousing. (Left hand)";
                                rightHand = false;

                                // Starting location for hand when doing mousetracking
                                skeletonCordX = player.LeftHand.X * MouseSensitivity + mouseCenterX;
                                skeletonCordY = (player.LeftHand.Y * -1) * MouseSensitivity + mouseCenterY;
                            }
                        }
                    }
                }
            }
            else
            { // try to get input from old player, see if player has gone missing or quits mousing
                bool playerLost = true;

                foreach (Player player in players)
                {
                    if (playerID == player.Id)
                    {
                        if (player.IsTracked)
                        {
                            if (((rightHand) && (player.RightShoulder.Z < (player.RightHand.Z + loseMouseControlTreshold)))
                                || ((!rightHand) && (player.LeftShoulder.Z < (player.LeftHand.Z + loseMouseControlTreshold))))
                            {
                                // TODO: DebugMessage = "Player " + playerID + " quit mousing.";
                                playerID = -1;
                                playerLost = false;
                            }
                            else
                            {
                                playerLost = false;

                                float handX;
                                float handY;
                                float shoulderX;
                                float shoulderY;
                                bool leftClick;
                                bool rightClick;
                                bool mouseDrag;

                                // TODO: support left and right click simultaneosly with second gesture ID? prioritize 1st? (harder to loose holding mousebutton down event)

                                if (rightHand)
                                {
                                    handX = player.RightHand.X;
                                    handY = player.RightHand.Y * -1f;

                                    if (player.RightShoulder.IsTracked)
                                    {
                                        shoulderX = player.RightShoulder.X;
                                        shoulderY = player.RightShoulder.Y * -1f;
                                    }
                                    else
                                    {
                                        shoulderX = 0f;
                                        shoulderY = 0f;
                                    }

                                    leftClick = ((player.RightHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.RightHand.HighGesture == HandGestures.A));
                                    rightClick = ((player.RightHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.RightHand.HighGesture == HandGestures.B));
                                    mouseDrag = ((player.RightHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.RightHand.HighGesture == HandGestures.Neutral));
                                }
                                else
                                {
                                    handX = player.LeftHand.X;
                                    handY = player.LeftHand.Y * -1f;

                                    if (player.LeftShoulder.IsTracked)
                                    {
                                        shoulderX = player.LeftShoulder.X;
                                        shoulderY = player.LeftShoulder.Y * -1f;
                                    }
                                    else
                                    {
                                        shoulderX = 0f;
                                        shoulderY = 0f;
                                    }

                                    leftClick = ((player.LeftHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.LeftHand.HighGesture == HandGestures.A));
                                    rightClick = ((player.LeftHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.LeftHand.HighGesture == HandGestures.B));
                                    mouseDrag = ((player.LeftHand.HighGestureAccuracy >= requiredGestureAccuracy) && (player.LeftHand.HighGesture == HandGestures.Neutral));
                                }

                                if (mouseDragging)
                                {
                                    if (leftClick || rightClick || mouseDrag)
                                    {
                                        if (leftClick)
                                        {
                                            SetCursor(leftCursor);
                                        }
                                        else if (rightClick)
                                        {
                                            SetCursor(RightCursor);
                                        }
                                        else
                                        {
                                            SetCursor(MoveCursor);
                                        }

                                        double newLocationX = handX * MouseSensitivity + mouseCenterX;
                                        double newLocationY = handY * MouseSensitivity + mouseCenterY;
                                        double changeX = newLocationX - skeletonCordX;
                                        double changeY = newLocationY - skeletonCordY;
                                        skeletonCordX = newLocationX;
                                        skeletonCordY = newLocationY;
                                        mouseCordX += changeX;
                                        mouseCordY += changeY;

                                        if (mouseCordX < 0D)
                                        {
                                            mouseCordX = 0D;
                                        }
                                        else if (mouseCordX > System.Windows.SystemParameters.PrimaryScreenWidth)
                                        {
                                            mouseCordX = System.Windows.SystemParameters.PrimaryScreenWidth;
                                        }

                                        if (mouseCordY < 0D)
                                        {
                                            mouseCordY = 0D;
                                        }
                                        else if (mouseCordY > System.Windows.SystemParameters.PrimaryScreenHeight)
                                        {
                                            mouseCordY = System.Windows.SystemParameters.PrimaryScreenHeight;
                                        }

                                        MouseFaker.MouseEvent((int)mouseCordX, (int)mouseCordY, leftClick, rightClick);
                                    }
                                    else
                                    {
                                        // TODO: DebugMessage = "Player " + playerID + " no longer gesturing!";
                                        SetCursor(waitCursor);
                                        playerID = -1;
                                    }
                                }
                                else
                                {
                                    // TODO
                                    //NativeMethods.SendMouseInput((int)(handX * MouseSensitivity + mouseCenterX), (int)(handY * MouseSensitivity + mouseCenterY), (int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, leftClick);

                                    if (leftClick)
                                    {
                                        SetCursor(leftCursor);
                                    }
                                    else if (rightClick)
                                    {
                                        SetCursor(RightCursor);
                                    }
                                    else
                                    {
                                        SetCursor(MoveCursor);
                                    }

                                    MouseFaker.MouseEvent((int)((handX-shoulderX) * MouseSensitivity + mouseCenterX), (int)((handY-shoulderY) * MouseSensitivity + mouseCenterY), leftClick, rightClick);
                                }
                            }
                        }
                        else
                        {
                            // TODO: DebugMessage = "Player " + playerID + " no longer tracked!";
                            SetCursor(waitCursor);
                            playerID = -1;
                        }
                    }
                }

                if (playerLost)
                {
                    // TODO: DebugMessage = "Player " + playerID + " lost!";
                    SetCursor(waitCursor);
                    playerID = -1;
                }
            }
        }
    }
}